package tcp

import (
	"io"
	"log"
	"net"
	"sync"
)

type Session struct {
	net.TCPConn
	*sessionHub
	head    *node
	tail    *node
	mu      *sync.Mutex
	sendCtx *SessionContext
	readCtx *SessionContext
}

func (s *Session) Send(buf *Buffer) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.sendCtx.SetCurrentNode(s.tail)
	s.tail.Write(s.sendCtx, buf)
}

func (s *Session) Close() {
	err := s.TCPConn.Close()
	if err != nil {
		return
	}
}

func (s *Session) String() string {
	return s.TCPConn.RemoteAddr().String()
}

func (s *Session) Read() {
	buff := NewBufferWithHead(s.ReadHeadSize, s.ReadBufferSize)

	s.fireConnected()

	for true {
		err := buff.Read(&s.TCPConn)

		if err != nil {
			if _, ok := err.(*net.OpError); !(ok || err == io.EOF) {
				log.Print(err.Error())
			}
			s.fireDisconnected()
			break
		}

		s.fireMessage(buff)

		buff.Reset()
	}

	buff = nil
}

func (s *Session) WatchRead() {
	go s.Read()
}

func (s *Session) fireMessage(buff *Buffer) {
	s.readCtx.SetCurrentNode(s.head)
	s.head.OnMessage(s.readCtx, buff)
}

func (s *Session) fireDisconnected() {
	s.readCtx.SetCurrentNode(s.head)
	s.head.OnDisconnected(s.readCtx)
}

func (s *Session) fireConnected() {
	s.readCtx.SetCurrentNode(s.head)
	s.head.OnConnected(s.readCtx)
}
